package io.lb.deng.webflux.web.security;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import io.lb.deng.webflux.web.component.JwtTokenProvider;
import reactor.core.publisher.Mono;

/**
 * 这个过滤器的主要功能是从请求中获取JWT，然后进行校验，把Authentication放进ReactiveSecurityContext里去
 * @author DengLibin
 * @Date ###### Sat Oct 2 11:31:34 CST 2021
 */
public class JwtTokenAuthenticationFilter implements WebFilter {

    public static final String HEADER_TOKEN = "token";

    private final JwtTokenProvider tokenProvider;

    public JwtTokenAuthenticationFilter(JwtTokenProvider tokenProvider) {
        this.tokenProvider = tokenProvider;
    }
    /**
     * 复写filter方法
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String token = resolveToken(exchange.getRequest());
        //校验token
        if (StringUtils.hasText(token) && this.tokenProvider.validateToken(token)) {
            Authentication authentication = getAuthenticationByToken(token);
            //把Authentication放进ReactiveSecurityContext里去
            return chain.filter(exchange)
                    .contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
        }
        return chain.filter(exchange);
    }

    /**
     * 根据token获取用户 认证信息 和授权信息
     * @param token
     * @return
     */
    private Authentication getAuthenticationByToken(String token) {
        Long userId = tokenProvider.getUserId(token);
        String permissions = tokenProvider.getRolePermissions(token);
        String username = tokenProvider.getUsername(token);
        return new UsernamePasswordAuthenticationToken(userId, username, AuthorityUtils.commaSeparatedStringToAuthorityList(permissions));
    }
    /**
     * 从请求头获取token
     * @param request
     * @return
     */
    private String resolveToken(ServerHttpRequest request) {
        return  request.getHeaders().getFirst(HEADER_TOKEN);
        
    }
    
}
